package function.client;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * client层抽象，封装共性逻辑
 *
 * @author G_Y, 2022/3/29 17:48
 **/
@Slf4j
abstract class AbstractClient2 {

    /**
     * 获取当前client-facade日志错误码
     *
     * @author G_Y, 2022/3/30 14:10
     **/
    abstract String getLogErrorCode();

    /**
     * client中facade方法委托执行器
     *
     * @param t                facade方法请求参数
     * @param facadeFunc       facade方法的function
     * @param resultCheckFunc  对result校验的function
     * @param facadeMethodName facade方法名称
     * @return facade调用的响应结果
     * @author G_Y, 2022/3/30 13:58
     **/
    <T, R> R invoke(T t, Function<T, R> facadeFunc, BiFunction<T, R, Boolean> resultCheckFunc, String facadeMethodName) {

        R r;
        try {
            r = facadeFunc.apply(t);
        } catch (Exception e) {
            log.error(LogUtils.errorLog("{} RPC调用出现异常：{}，req={}", this.getLogErrorCode()),
                    facadeMethodName, e.getMessage(), JSON.toJSONString(t), e);
            return null;
        }

        if (log.isDebugEnabled()) {
            log.debug("{} RPC调用，req={}, resp={}", facadeMethodName, JSON.toJSONString(t), JSON.toJSONString(r));
        }

        if (Objects.isNull(r)) {
            // rpc调用结果，一般不会什么都不返回
            log.error(LogUtils.errorLog("{} RPC调用，响应结果result为空，不符合预期，req={}，resp=null", this.getLogErrorCode()),
                    facadeMethodName, JSON.toJSONString(t));
            return null;
        }

        if (r instanceof RpcResult) {
            RpcResult rpcResult = (RpcResult) r;
            if (rpcResult.isFailed()) {
                // 响应结果为：失败
                log.error(LogUtils.errorLog("{} RPC调用，结果失败，req={}，resp={}", this.getLogErrorCode()),
                        facadeMethodName, JSON.toJSONString(t), JSON.toJSONString(r));
                return null;
            }
        }

        boolean pass = resultCheckFunc.apply(t, r);

        if (!pass) {
            // 结果校验不通过
            log.error(LogUtils.errorLog("{} RPC调用，结果不符合业务预期或约定，req={}，resp={}", this.getLogErrorCode()),
                    facadeMethodName, JSON.toJSONString(t), JSON.toJSONString(r));
            return null;
        }

        // 到这里时，返回的结果一定是业务中可以直接使用的数据（符合期望的结果）
        return r;

    }

}
